using System;
using System.Collections.Generic;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace TfsCodeReviewPolicy
{
    [Serializable]
    public class CodeReviewPolicy : PolicyBase
    {
        #region Constants

        private const string POLICY_DESCRIPTION = "Enforces that any code check-in must be associated with a Buddy Build work item which has been marked approved by a successful buddy build.";
        private const string POLICY_TYPE = "TFS Buddy Build Policy";
        //private const string INSTALLATION_INSTRUCTIONS = "\n\n" +
        //                " 1. Locate the latest build on TfsBuddyBuildPolicy.dll and place it locally on client. \n" +
        //               @" 2. For VS2005: Add location to HKLM\SOFTWARE\Microsoft\VisualStudio\8.0\TeamFoundation\SourceControl\Checkin Policies\" + "\n" +
        //               @" NOTE: On 64bit machines, the path is: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\8.0\TeamFoundation\SourceControl\Checkin Policies" + "\n" +
        //               @" If installing on VS2008, substitute 8.0 with 9.0 in the registry keys above.";
        private const string INSTALLATION_INSTRUCTIONS = "\n\n" +
                        "To install the Buddy Build TFS Policy: \n" +
                        "Go to: http://www.tfsbugger.com/dev/downloads/" + "\n" +
                        "And download the appropriate policy for your Visual Studio version and operating system flavor (32-bit or 64-bit)." + "\n\n" +
                        "For any other issues, go to: http://www.tfsbugger.com/dev/faq/faq.htm.";
        private const string POLICY_FAILURE_NO_ASSOCIATED_BUDDY_BUILD_WORKITEM = "There is no associated Buddy Build Work Item for this check in.";
        private const string POLICY_FAILURE_ASSOCIATED_BUDDY_BUILD_WORKITEMS_NOT_APPROVED = "The associated Buddy Build work item is not marked as Approved.";
        private const string POLICY_FAILURE_ONLY_ONE_BUDDY_BUILD_WORKITEM_ALLOWED = "Only one Buddy Build work item can be associated with a check-in.";
        private const string POLICY_FAILURE_WORKITEM_ALREADY_CLOSED = "Associated buddy build work item is already 'Closed'. Associated buddy build work items should be Resolved/Approved.";
        private const string BUDDY_BUILD_WORKITEM_TYPENAME = "Buddy Build";
        private const string STATE_CLOSED = "Closed";
        private const string STATE_RESOLVED = "Resolved";
        private const string RESOLUTION_APPROVED = "Approved";
        private const string WORKITEM_RESOLUTION_FIELDNAME = "Resolution";
        
        #endregion Constants

        #region Overrides

        public override string Description
        {
            get { return POLICY_DESCRIPTION; }
        }

        public override string Type
        {
            get { return POLICY_TYPE; }
        }

        public override string TypeDescription
        {
            get { return POLICY_DESCRIPTION; }
        }

        public override bool CanEdit
        {
            get
            {
                return false;
            }
        }

        public new string InstallationInstructions
        {
            get
            {
                return INSTALLATION_INSTRUCTIONS;
            }
        }

        public override bool Edit(IPolicyEditArgs policyEditArgs)
        {
            return true;
        }
                
        public override PolicyFailure[] Evaluate()
        {
            List<PolicyFailure> failures = new List<PolicyFailure>();

            bool foundBuddyBuildWorkItem = false;
            bool buddyBuildApproved = true;
            bool workitemAlreadyClosed = false;
            int buddyBuildWorkItemCount = 0;

            foreach (WorkItemCheckinInfo wiInfo in PendingCheckin.WorkItems.CheckedWorkItems)
            {
                if (wiInfo.WorkItem.Type.Name == BUDDY_BUILD_WORKITEM_TYPENAME)
                {
                    buddyBuildWorkItemCount++;
                    // Check the work item resolution status.
                    foundBuddyBuildWorkItem = true;
                    if (wiInfo.WorkItem.State == STATE_CLOSED)
                    {
                        workitemAlreadyClosed = true;
                        break;
                    }
                    else
                    {
                        if (wiInfo.WorkItem.State == STATE_RESOLVED)
                        {
                            if ((string)wiInfo.WorkItem.Fields[WORKITEM_RESOLUTION_FIELDNAME].Value == RESOLUTION_APPROVED)
                            {
                                if (wiInfo.WorkItem.State == STATE_RESOLVED)
                                {
                                    //try
                                    //{
                                    //    wiInfo.WorkItem.State = STATE_CLOSED;
                                    //    wiInfo.WorkItem.Save();
                                    //}
                                    //catch { /* This function sometimes gets called twice */}
                                }
                            }
                            else
                            {
                                buddyBuildApproved = false;
                            }
                        }
                        else
                        {
                            buddyBuildApproved = false;
                        }
                    }
                }
            }

            if (!foundBuddyBuildWorkItem) failures.Add(new PolicyFailure(POLICY_FAILURE_NO_ASSOCIATED_BUDDY_BUILD_WORKITEM, this));
            if (workitemAlreadyClosed) failures.Add(new PolicyFailure(POLICY_FAILURE_WORKITEM_ALREADY_CLOSED, this));
            if (buddyBuildWorkItemCount > 1)
                failures.Add(new PolicyFailure(POLICY_FAILURE_ONLY_ONE_BUDDY_BUILD_WORKITEM_ALLOWED, this));
            else
            {
                if (!buddyBuildApproved) failures.Add(new PolicyFailure(POLICY_FAILURE_ASSOCIATED_BUDDY_BUILD_WORKITEMS_NOT_APPROVED, this));
            }

            return failures.ToArray();
        }

        #endregion Overrides

    }
}
